<?php

namespace App\Services\User\User;

use App\Http\Controllers\Admin\AliController;
use App\Models\User\Role;
use App\Models\User\User;
use App\Models\User\UsersInfo;
use App\Models\User\Users;
use App\Services\User\RoleGroup\RoleGroupLogic;
use App\Services\User\Token\TokenLogic;
use App\Services\User\Traits\Password;
use App\Services\User\ValidateUser;
use Illuminate\Hashing\BcryptHasher;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * 用户服务 逻辑层
 * Class UserLogic
 * @package App\Services\User\User
 */
class UserLogic {

    use Password;

    /**
     * 用户登录 自动登录 非自动登录
     * @param array $data
     * @param bool $is_auto_login
     * @return array
     * @throws \App\Exceptions\RequestFailException
     */
    protected function _login(array $data, bool $is_auto_login = false): array
    {
        # 验证
        ValidateUser::checkValidate($data, ['name', 'phone', 'login_password', 'token', 'is_auto_login']);
        $TokenLogic = new TokenLogic();
        $tokenContent = $TokenLogic->hGetAll($data['token']);
        if($tokenContent['status'] != SUCCESS_STATUS){
            return $tokenContent;
        }
        // 先根据用户的name || phone 去user表取用户信息 //
        !empty($data['name']) ? $_where['name'] = $data['name'] : null;
        !empty($data['phone']) ? $_where['phone'] = $data['phone'] : null;
        !empty($data['id']) ? $_where['id'] = $data['id'] : null;
        if(!isset($_where)){
            return verify_err(null, '没有找到查询条件id,name,phone');
        }

        $info = User::where($_where)->first();

        if(!$info){
            $this->_addNoUserErrCounts($data, $TokenLogic);//在token中将no_user_err_counts次数加一
            return verify_err(null, '该用户不存在');
        }

        //自动登录时，检验登录数据
        if($is_auto_login && ($info['auto_login_token'] != $data['auto_login_token'] || $info['auto_login_time'] != $data['auto_login_time']) ){
            return verify_err(null, '自动登录参数错误！存在账号被窃取的风险');
        }
        $info = $info->toArray();
        //自动登录跳过登录密码检验(不需要输入的密码的为自动登录)
        if(!$is_auto_login){
            $judge = $this->checkLoginPassword($data, $info);
            if(SUCCESS_STATUS !== $judge['status']){
                $this->_addNoUserErrCounts($data, $TokenLogic);//在token中将no_user_err_counts次数加一
                return $this->_errLoginAfter($info, $judge['msg'], $tokenContent['res']['no_user_err_counts']);  //执行登录失败后的操作
            }
        }

        unset($info['login_password'], $info['login_salt'], $info['pay_password'], $info['pay_salt']);

        $autoLoginUserInfo = $info;
        unset($info['auto_login_time'], $info['auto_login_token']);

        // 将用户的角色组信息拆分和角色信息合并
        $idsInfo = (new RoleGroupLogic())->roleGroupIdsToRoleIds(['group_ids'=>$info['role_group_ids']]);
        $roleIds = SUCCESS_STATUS === $idsInfo['status'] ? $idsInfo['res']['autoRes'] : '';
        $roleIds .= ',' . $info['role_ids'];
        $roleIds = implode(',', array_unique(explode(',', trim($roleIds, ','))));

        $roleNames = Role::whereIn('id', explode(',', $roleIds))->where('status', '1')->pluck('name')->toArray();

        // 需要将用户信息保存在redis 的token中
        $addRolesRes =  (new TokenLogic())->addRoles(['token'=>$data['token'], 'roles'=>implode(',',$roleNames)]);

        //将token存session
        session('request_token', $data['token']);

        if($addRolesRes['status'] != SUCCESS_STATUS){
            return $this->_errLoginAfter($info, $addRolesRes['msg'], $tokenContent['res']['no_user_err_counts']); //执行登录失败后的操作
        }

        $addInfoRes = (new TokenLogic())->hMset(['token'=>$data['token'], 'arr'=>$info]);
        if($addInfoRes['status'] != SUCCESS_STATUS){
            return $this->_errLoginAfter($info, $addInfoRes['msg'], $tokenContent['res']['no_user_err_counts']);  //执行登录失败后的操作
        }

        //登录登录与非自动登录成功后的调用
        if($is_auto_login){
            $info['other_info'] = json_decode($info['other_info'], true);
            return $this->_successAutoLoginAfter($info, $data);
        }else{
            $autoLoginUserInfo['other_info'] = json_decode($autoLoginUserInfo['other_info'], true);
            return $this->_successLoginAfter($autoLoginUserInfo, $data);
        }
    }
    /*用户名不存在或密码输入错误，更新token中的no_user_err_counts字段+1*/
    protected function _addNoUserErrCounts($data, $TokenLogic = null): array
    {
        $TokenLogic = $TokenLogic ?? new TokenLogic();

        $tokenContent = $TokenLogic->hGetAll($data['token']);
        if($tokenContent['status'] != SUCCESS_STATUS){
            return $tokenContent;
        }
        $noUserErrCounts = $tokenContent['res']['no_user_err_counts'] + 1;
        $res = $TokenLogic->hMset(['token'=>$data['token'], 'arr'=>['no_user_err_counts'=>$noUserErrCounts]]);
        return $res;
    }
    // 用户登录
    public function login(array $data): array
    {
        return $this->_login($data, false);
    }
//
//    //用户自动登录
//    public function autoLogin(array $data): array
//    {
//        return $this->_login($data, true);
//    }
//
    //登录失败后的执行方法为：判断是否操作频繁 更新最后错误登录时间 + 错误次数增1
    protected function _errLoginAfter($userInfo, $errMsg, $noUserErrCounts): array
    {
        if($userInfo['last_err_login_time'] && ( bcsub(NOW, $userInfo['last_err_login_time']) < MAX_LOGIN_RATE )){
            $errMsg = '操作过于频繁，请' . MAX_LOGIN_RATE . '秒之后再试';
        }
        $saveData['login_err_times'] = $userInfo['login_err_times'] + 1;
        $saveData['last_err_login_time'] = NOW;

        $updateRes = User::where('id', $userInfo['id'])->update($saveData);
//        $updateRes = $this->model($this->userModel)->save($saveData, ['id'=>$userInfo['id']]);
        $saveData['max_login_err_times'] = MAX_LOGIN_ERR_TIMES;
        $saveData['no_user_err_counts'] = $noUserErrCounts + 1;
        return verify_err($saveData, $errMsg);
    }

    /*非自动登录成功后的执行方法为：错误登录次数、最后错误登录时间分别置0 并返回用户信息
      所有返回用户信息的方法中，除infoAll方法，仅该方法在第一次打勾自动登录时返回了auto_login_token auto_login_time
    */
    protected function _successLoginAfter($userInfo, $data): array
    {
        $saveData['login_err_times'] = 0;
        $saveData['last_err_login_time'] = 0;
        $saveData['is_auto_login'] = $data['is_auto_login'];
        $saveData['auto_login_time'] = $data['is_auto_login'] ? NOW : 0;
        $saveData['auto_login_token'] = $data['is_auto_login'] ? $data['token'] : '';


        $updateRes = User::where('id', $userInfo['id'])->update($saveData);
        if($data['is_auto_login'] && !$userInfo['auto_login_token']){
            $userInfo = array_merge($userInfo, $saveData);
        }else{
            unset($userInfo['auto_login_token'], $userInfo['auto_login_time']);
        }
        return auto_success($userInfo, '登录成功');
    }

    /*自动登录成功后的执行方法*/
    protected function _successAutoLoginAfter($userInfo, $data): array
    {
        $saveData['login_err_times'] = 0;
        $saveData['last_err_login_time'] = 0;
        $saveData['auto_login_token'] = $data['token'];

        $updateRes = User::where('id', $userInfo['id'])->update($saveData);
        unset($userInfo['auto_login_token'], $userInfo['auto_login_time']);
        return auto_success($userInfo, '登录成功');
    }
//
//    //自动登录超时后的处理
//    public function autoLoginOvertime($data): array
//    {
//        $saveData['is_auto_login'] = 0;
//        $saveData['auto_login_time'] = 0;
//        $saveData['auto_login_token'] = '';
//        $res = $this->model($this->userModel)->save($saveData, ['name'=>$data['name']]);
//        return auto_return($res);
//    }
//
//    // 用户注册
//    public function register(array $data): array
//    {
//        //注册时判断手机号是否唯一
//        $userInfo = $this->model($this->userModel)->where(['phone'=>$data['phone']])->find();
//        if($userInfo){
//            return verify_err(null, '该手机号已存在');
//        }
//        $checkName = $this->model($this->userModel)->where(['name'=>$data['name']])->find();
//        if($checkName){
//            return verify_err(null, '该用户名已存在');
//        }
//
//        $loginPasswordArr = $this->_makeLoginPassword($data['login_password']);
//        $data = array_merge($data, $loginPasswordArr);
//        $data['role_ids'] = config('append_role_ids');
//        $data['role_group_ids'] = config('append_role_group_ids');
//        $data['status'] = USER_REGISTER_STATUS;
//        $data['update_login_pwd_time'] = NOW;
//        $data['update_pay_pwd_time'] = NOW;
//        try{
//            $res = $this->model($this->userModel)->save($data);
//            $res = $this->model($this->userModel)->getLastInsID();
//        }catch (\Exception $e) {
//            // 当唯一键重复等报错时
//            return server_err(null, '数据库异常:' . $e->getMessage());
//        }
//
//        return auto_return($res, '用户注册成功', '用户注册失败');
//    }
    // 根据id name phone 三者之一获取用户信息,不包含密码信息
    public function info(array $data): array
    {
        $_where = make_map($data, ['name', 'id', 'phone']);
        if(!empty($_where['name'])){
            $where=['user.name'=>$_where['name']];
        }
        if(!empty($_where['id'])){
            $where=['user.id'=>$_where['id']];
        }
        $info = User::join('department', 'user.department', '=', 'department.id')
        ->join('role', 'user.role_ids', '=', 'role.id')
        ->where($where)
        ->select('department.name_cn as department_name', 'user.*','role.name_cn as work');
        $info->hidden = ['id', 'login_password', 'login_salt', 'pay_password', 'pay_salt', 'auto_login_time', 'auto_login_token'];
        $info = $info->first();
        if(!empty($info)){
           $info = $info->toArray();
        }
        if(isset($data['is_add_no_user_counts']) && $data['is_add_no_user_counts'] == 1 && !$info) {
            $this->_addNoUserErrCounts($data);
        }
        if($info){
            $info['other_info'] = json_decode($info['other_info'], true);
            $info['authen_status'] = (int) $info['other_info']['authen_status'];
            $info['authen_status_text'] = $this->_getAuthenStatusText($info['authen_status']);
        }
        return auto_return($info, '成功找到用户信息', '没有找到用户信息');
    }
    // 根据 ID ||用户名 || 手机号 获取某一用户包含自动登录的用户全部信息
    public function infoAll(array $data): array
    {
        $_where = make_map($data, ['name', 'id', 'phone']);
        $query = User::where($_where);
        $query->hidden=['login_password','login_salt','pay_password','pay_salt'];
        $info =$query ->first()->toArray();
        $info && $info['other_info'] = json_decode($info['other_info'], true);
        return auto_return($info, '成功找到用户信息', '没有找到用户信息');
    }
//    // 完善用户信息
//    public function perfect(array $data): array
//    {
//        $_where = make_map($data, ['name', 'id', 'phone']);
//        $res = $this->model($this->userModel)
//            ->save(['other_info' => $data['other_info']], $_where);
//        return auto_return($res, '成功完善用户信息', '完善用户信息失败');
//    }
//    // 给某一个用户某角色
    public function giveRoles(array $data): array
    {
        // 先查询原来的信息
        $info = $this->info($data);
        if (SUCCESS_STATUS !== $info['status']) {
            return $info;
        }
        $save['role_ids'] = $data['role_id'];
        // 再加新加的角色合并
        if ($info['res']['role_ids']) {
            $oldRoles = explode(',', $info['res']['role_ids']);
            $oldLen = count($oldRoles);
            array_push($oldRoles, $save['role_ids']);
            $newRoles = array_unique($oldRoles);
            if (count($newRoles) === $oldLen) {
                return null_data(null, '用户已有该角色,无需新增');
            }
            sort($newRoles);
            $save['role_ids'] = implode(',', $newRoles);
        }
        // 保存条件
        $_where = make_map($data, ['name', 'id', 'phone']);
        $res = User::where($_where)
            ->update($save);
        return auto_return($res, '成功给某一个用户某些角色','给某一个用户某些角色失败');
    }
    // 移除某用户的某角色
    public function removeUserRole(array $data): array
    {
        // 先查询原来的信息
        $info = $this->info($data);
        if (SUCCESS_STATUS !== $info['status']) {
            return $info;
        }
        $roleIdsArr = array_unique(explode(',', $info['res']['role_ids']));
        $newRoleIdsArr = array_diff($roleIdsArr, [$data['role_id']]);
        sort($newRoleIdsArr);
        $newRoleIds = implode(',', $newRoleIdsArr);
        $_where = \make_map($data, ['id', 'name', 'phone']);
        $res = User::where($_where)
            ->update(['role_ids'=>$newRoleIds]);
        return \auto_return($res, '成功移除某用户的某角色', '移除某用户的某角色失败');
    }

    // 用户审核通过
    public function passAudit(array $data): array
    {
        $_where = make_map($data, ['name','id','phone']);
        $res = User::where($_where)
            ->update(['status' => '1']);
        return auto_return($res, '成功用户审核', '用户审核失败');
    }

    // 用户列表
    public function list(array $data): array
    {
        $query = User::join('department', 'user.department', '=', 'department.id')
        ->join('role', 'user.role_ids', '=', 'role.id')
        ->orderBy('user.id','desc');
        $query->where('user.id', '<', 1000);
        if(isset($data['keywords']) && $data['keywords'] !== '' && $data['authen_status'] == ''){
            $query->where('id','like',"%".$data['keywords']."%")->orWhere('name','like',"%".$data['keywords']."%")->orWhere('nickname','like',"%".$data['keywords']."%")->orWhere('phone','like',"%".$data['keywords']."%");
        }
        if(isset($data['authen_status']) && $data['authen_status'] !== '' && $data['keywords'] == ''){
            $query->where('other_info->authen_status',(int)$data['authen_status']);
        }
        if(isset($data['authen_status']) && $data['authen_status'] !== '' && isset($data['keywords']) && $data['keywords'] !== ''){
            $keyword = $data['keywords'];
            $query->where('other_info->authen_status',(int)$data['authen_status']);
            $query->where(function ($query) use ($keyword) {
                $query->where('id','like',"%".$keyword."%")->orWhere('name','like',"%".$keyword."%")->orWhere('nickname','like',"%".$keyword."%")->orWhere('phone','like',"%".$keyword."%");
            });
        }
        $query->hidden=['login_password','login_salt','pay_password','pay_salt','auto_login_time','auto_login_token'];

        $list=$query->select('department.name_cn as department_name', 'user.*','role.name_cn as work')
           // ->paginate($data['list_rows'], null, null, $data['page']);
           ->paginate(10);

//        if($list['total'] > 0){
//            foreach ($list['data'] as $k => &$v) {
//                $v['other_info'] = $other_info = json_decode($v['other_info'], true);
//                $v['authen_status'] = (int)$other_info['authen_status'];
//                if(isset($other_info['authen_status'])){
//                    $v['authen_status_text'] = $this->_getAuthenStatusText($other_info['authen_status']);
//                }else{
//                    $v['authen_status_text'] = '';
//                }
//
//            }
//        }
        //dd($list);
        return auto_success($list, '成功获取用户列表', '获取用户列表失败');
    }

    // 编辑用户信息
    public function edit(array $data): array
    {
        $save = make_map($data, ['name', 'nickname', 'sex', 'head_portrait', 'phone', 'row_ids','row_group_ids','other_info'], '');
        if(array_eq($save, '')){ return verify_err($save, '至少输入一条要编辑的用户信息'); }
        $res = User::where(['id'=>$data['id']])
             ->update($save);
        //更新token里的内容
        if(isset($data['token']) && $data['token']){
            $newUserInfo = User::where(['id'=>$data['id']])->first();
            if(!$newUserInfo){ return null_data(null, '没有相关用户信息'); }
            $newUserInfo = $newUserInfo->toArray();
            unset($newUserInfo['login_password'], $newUserInfo['login_salt'], $newUserInfo['pay_password'], $newUserInfo['pay_salt'], $newUserInfo['auto_login_token'], $newUserInfo['auto_login_time']);
            $tokenObj = new TokenLogic();
            $updateTokenRes = $tokenObj->hMset(['token'=>$data['token'], 'arr'=>$newUserInfo]);
        }

        return auto_return($res, '成功编辑用户信息', '编辑用户信息失败');
    }
    // 验证登录密码
    public function checkLoginPassword(array $data): array
    {
        // 查找用户信息
        $_where = make_map($data, ['name','id','phone']);
        $_where['status'] = '1';
        $info = User::where($_where)->select('login_password', 'login_salt')->first()->toArray();
        if(!$info){ return verify_err(null, '没有相关用户信息'); }
        // 验证登陆密码
        //dd($data['login_password'] ,  $info);
        $check = $this->_checkLoginPassword($data['login_password'],(array) $info);
        return auto_return($check, '登陆密码正确', '登陆密码错误');
    }
    // 验证支付密码
    public function checkPayPassword(array $data): array
    {
        // 查找用户信息
        $_where = make_map($data, ['name','id','phone']);
        $_where['status'] = '1';
        $info = User::select('pay_password','pay_salt')
            ->where($_where)
            ->first()
            ->toArray();
        if(!$info){
            return verify_err(null, '没有相关用户信息');
        }else if($info['pay_password'] === ''){
            return verify_err(null, '您还没有设置支付密码');
        }
        // 验证支付密码
        $check = $this->_checkPayPassword($data['pay_password'], $info);
        return auto_return($check, '支付密码正确', '支付密码错误');
    }
    // 修改登录密码
    public function editLoginPassword(array $data): array
    {
        // 验证登录密码
        $checkData = $data;
        $checkData['login_password'] = $data['old_login_password'];
        $checkRes = $this->checkLoginPassword($checkData);
        if(SUCCESS_STATUS !== $checkRes['status']){ return $checkRes; }
        // 修改登录密码
        $newData = $this->_makeLoginPassword($data['login_password']);
        isset($data['update_login_pwd_time']) && $newData['update_login_pwd_time'] = $data['update_login_pwd_time'];
        $_where = make_map($data, ['name','id','phone']);
        $_where['status'] = '1';
        $res = User::where($_where)->update($newData);
        return auto_return($res, '成功修改登录密码', '修改登录密码失败');
    }
    // 修改支付密码
    public function editPayPassword(array $data): array
    {
        // 验证支付密码
        $checkData = $data;
        $checkData['pay_password'] = $data['old_pay_password'];
        $checkRes = $this->checkPayPassword($checkData);
        if(SUCCESS_STATUS !== $checkRes['status']){ return $checkRes; }
        // 修改支付密码
        $newData = $this->_makePayPassword($data['pay_password']);
        isset($data['update_pay_pwd_time']) && $newData['update_pay_pwd_time'] = $data['update_pay_pwd_time'];
        $_where = make_map($data, ['name','id','phone']);
        $_where['status'] = '1';
        $res = User::where($_where)->update($newData);
        return auto_return($res, '成功修改支付密码', '修改支付密码失败');
    }
//    // 初始化用户支付密码 在用户没有设置支付密码的情况下
//    public function initPayPassword(array $data): array
//    {
//        // 先验证登录密码是否正确
//        $checkRes = $this->checkLoginPassword($data);
//        if(SUCCESS_STATUS !== $checkRes['status']){ return $checkRes; }
//        // 先查询用户的是否设置过支付密码
//        $_where = make_map($data, ['name','id','phone']);
//        $payPassword = $this->db()->where($_where)->value('pay_password');
//        if('' !== $payPassword){ return verify_err(null, '已存在支付密码不能初始化'); }
//        // 把空密码也作为where条件之一
//        $_where['status'] = '1';
//        $_where['pay_password'] = '';
//        $payPasswordArr = $this->_makePayPassword($data['pay_password']);
//        $res = $this->model($this->userModel)
//            ->where($_where)
//            ->update($payPasswordArr);
//        return auto_return($res, '成功初始化用户支付密码', '初始化用户支付密码失败');
//    }
    // 重置用户登录密码-中间层验证手机验证码通过后再调用本方法
    public function resetLoginPassword(array $data, bool $resetUser = true): array
    {
        // 先判断用户是否存在
        $findInfo = $this->info($data);
        if(SUCCESS_STATUS !== $findInfo['status']){ return $findInfo; }
        if ($resetUser && $findInfo['res']['id'] <= MAX_SYSTEM_ID) {
            return verify_err($findInfo['res']['id'], '无权重置管理员帐户' . $findInfo['res']['name']);
        }
        $loginPasswordArr = $this->_makeLoginPassword($data['login_password']);
        $_where = make_map($data, ['name','id','phone']);
        $res = User::where($_where)
            ->update($loginPasswordArr);
        return auto_return($res, '成功重置用户登录密码', '重置用户登录密码失败');
    }
    // 重置用户支付密码-中间层验证手机验证码通过后再调用本方法
    public function resetPayPassword(array $data, bool $resetUser = true): array
    {
        // 先判断用户是否存在
        $findInfo = $this->info($data);
        if(SUCCESS_STATUS !== $findInfo['status']){ return $findInfo; }
        if ($resetUser && $findInfo['res']['id'] <= MAX_SYSTEM_ID) {
            return verify_err($findInfo['res']['id'], '无权重置管理员帐户' . $findInfo['res']['name']);
        }
        $payPasswordArr = $this->_makePayPassword($data['pay_password']);
        $_where = make_map($data, ['name','id','phone']);
        $res = User::where($_where)
            ->update($payPasswordArr);
        return auto_return($res, '成功重置用户支付密码', '重置用户支付密码失败');
    }
    // 根据用户传入的IDS获取用户信息
    public function infoByIds(array $data): array
    {
        $len = count(explode(',', $data['ids']));
        $_where['status'] = '1';
        $query = User::where($_where);
        $query->hidden = ['login_password','login_salt','pay_password','pay_salt','auto_login_time','auto_login_token'];
        $ids=explode(",",$data['ids']);
        //dd($ids);
        $res = $query->whereIn('id', $ids)->orderByRaw(DB::raw("FIELD(id, ".implode(',', $ids).')'))->get()->toArray();
        $resLen = count($res);
        if ($len === $resLen) {
            return auto_success($res, '成功获取相关用户信息');
        } else {
            return auto_failure($res, '查询' . $len . '个id,获取' . $resLen . '条用户信息');
        }
    }
//    // 用户退出登录
    public function logout(array $data): array
    {
        $deleteRes = TokenLogic::delete($data);
        return $deleteRes['status'] === SUCCESS_STATUS
            ? \auto_success(null, '用户退出登录成功')
            : \auto_failure(null, '用户退出登录失败:' . $deleteRes['msg'] . '或token不存在');
    }
    // 用户更改自己的信息
    public function editSelfInfo(array $data): array
    {
        // 根据token找到用户的ID
        $tokenObj = new TokenLogic();
        $tokenRes = $tokenObj -> hGetAll($data['token']);
        if(SUCCESS_STATUS !== $tokenRes['status']){
            return $tokenRes;
        } else if (!isset($tokenRes['res']['id'])) {
            return verify_err(null, '此token没有找到相关用户ID');
        }

        // 将相关信息保存到数据库
        $newData = make_map($data, ['nickname', 'sex', 'head_portrait'], '');
        $newData['id'] = $tokenRes['res']['id'];
        $newData['token'] = $data['token'];
        $res = $this->edit($newData);
        return $res['status'] ? auto_success($res['res'], '用户更改自己的信息成功') :  auto_failure(null, '用户更改自己的信息失败');
    }
    // 用户更改自己的登录密码
    public function editSelfLoginPassword(array $data): array
    {
        // 根据token找到用户的ID
        $tokenObj = new tokenLogic();
        $tokenRes = $tokenObj->hGetAll($data['token']);
        if(SUCCESS_STATUS !== $tokenRes['status']){
            return $tokenRes;
        } else if (!isset($tokenRes['res']['id'])) {
            return verify_err(null, '此token没有找到相关用户ID');
        }
        // 将相应信息发送给相关接口
        $newData = make_map($data, ['login_password', 'old_login_password', 're_login_password'], '');
        $newData['id'] = $tokenRes['res']['id'];
        $newData['update_login_pwd_time'] = NOW;
        $res = $this->editLoginPassword($newData);
        return $res;
//        return $res['status'] ? auto_success($res['res'], '用户更改自己的登录密码成功') :  auto_failure(null, '用户更改自己的登录密码失败');
    }
    // 管理员重置普通用户密码
    public function resetUserLoginPassword(array $data): array
    {
        return $this->resetLoginPassword($data, true);
    }
    // 超级管理员重置所有用户密码的接口
    public function resetAllLoginPassword(array $data): array
    {
        return $this->resetLoginPassword($data, false);
    }
    // 用户更改自己的支付密码
    public function editSelfPayPassword(array $data): array
    {
        // 根据token找到用户的ID
        $tokenObj = new TokenLogic();
        $tokenRes = $tokenObj->hGetAll($data['token']);
        if(SUCCESS_STATUS !== $tokenRes['status']){
            return $tokenRes;
        } else if (!isset($tokenRes['res']['id'])) {
            return verify_err(null, '此token没有找到相关用户ID');
        }
        // 将相应信息发送给相关接口
        $newData = make_map($data, ['pay_password', 'old_pay_password', 're_pay_password'], '');
        $newData['id'] = $tokenRes['res']['id'];
        $newData['update_pay_pwd_time'] = NOW;
        $res = $this->editPayPassword($newData);
        return $res['status'] ? auto_success($res['res'], '用户更改自己的支付密码成功') :  auto_failure(null, '用户更改自己的支付密码失败:' . $res['msg']);
    }
    // 管理员重置普通用户支付密码
    public function resetUserPayPassword(array $data): array
    {
        return $this->resetPayPassword($data, true);
    }
    // 管理员重置所有用户支付密码
    public function resetAllPayPassword(array $data): array
    {
        return $this->resetPayPassword($data, false);
    }
//
//    //用户更改自己的用户基本信息
//    public function updateUserInfo(array $data): array
//    {
//        // 根据token找到用户的ID
//        $tokenRes = $this->logic($this->tokenLogic)->hGetAll($data);
//        if(SUCCESS_STATUS !== $tokenRes['status']){
//            return $tokenRes;
//        } else if (!isset($tokenRes['res']['id'])) {
//            return verify_err(null, '此token没有找到相关用户ID');
//        }
//
//        $userInfo = $this->db()->where(['id'=>$tokenRes['res']['id']])->find();
//        $other_info = json_decode($data['other_info'], true);
//        $db_other_info = json_decode($userInfo['other_info'], true);
//        $authen_status = $db_other_info['authen_status'] ?? '-1';
//        if(isset($other_info['real_name']) && in_array($authen_status,['0','1']) && $other_info['real_name'] != $db_other_info['real_name'] ){
//            return verify_err(null, '真实姓名请和实名认证时的姓名保持一致！');
//        }
//        isset($other_info['birthday']) && $db_other_info['birthday'] = $other_info['birthday'];
//        isset($other_info['email']) && $db_other_info['email'] = $other_info['email'];
//        isset($other_info['real_name']) && $db_other_info['real_name'] = $other_info['real_name'];
//
//        // 将相关信息保存到数据库
//        $newData = make_map($data, ['nickname', 'sex', 'head_portrait'], '');
//        $newData['other_info'] = json_encode($db_other_info);
//        $newData['id'] = $tokenRes['res']['id'];
//        $newData['token'] = $data['token'];
//        $res = $this->edit($newData);
//        return $res['status'] ? auto_success($res['res'], '用户更改自己的信息成功') :  auto_failure(null, '用户更改自己的信息失败');
//    }
//
//    //用户进行实名认证
//    public function authentication(array $data): array
//    {
//        // 根据token找到用户的ID
//        $tokenRes = $this->logic($this->tokenLogic)->hGetAll($data);
//        if(SUCCESS_STATUS !== $tokenRes['status']){
//            return $tokenRes;
//        } else if (!isset($tokenRes['res']['id'])) {
//            return verify_err(null, '此token没有找到相关用户ID');
//        }
//        $other_info = json_decode($tokenRes['res']['other_info'], true);
//        if(in_array($other_info['authen_status'], ['0','1'])){
//            return verify_err(null, '您已提交过认证信息');
//        }
//
//        $authentication['id_number'] = $data['id_number'];
//        $authentication['front_img'] = $data['front_img'];
//        $authentication['back_img'] = $data['back_img'];
//        $authentication['create_time'] = NOW;
//        $authentication['update_time'] = NOW;
//        $new_other_info['authentication'] = $authentication;
//        $new_other_info['authen_status'] = 0;  // 认证状态 -1 未提交 0 待审核 1 审核通过 2 审核失败
//        $new_other_info['real_name'] = $data['real_name'];
//        $data['other_info'] = json_encode(array_merge($other_info, $new_other_info));
//        $data['id'] = $tokenRes['res']['id'];
//        $res = $this->edit($data);
//        if($res['status'] != SUCCESS_STATUS){
//            return auto_failure(null, '提交认证信息失败');
//        }
//        return auto_success($res['res'], '提交认证信息成功');
//
//    }
//    /*用户进行换绑手机*/
//    public function changePhone(array $data): array
//    {
//        // 根据token找到用户的ID
//        $tokenRes = $this->logic($this->tokenLogic)->hGetAll($data);
//        if(SUCCESS_STATUS !== $tokenRes['status']){
//            return $tokenRes;
//        } else if (!isset($tokenRes['res']['id'])) {
//            return verify_err(null, '此token没有找到相关用户ID');
//        }
//
//        $newData = make_map($data, ['phone'], '');
//        $newData['id'] = $tokenRes['res']['id'];
//        $newData['token'] = $data['token'];
//        try{
//            $res = $this->edit($newData);
//        }catch(\Exception $e){
//            return server_err(null, '数据库错误' . $e->getMessage() );
//        }
//        return $res['status'] ? auto_success($res['res'], '换绑手机号成功') :  auto_failure(null, '换绑手机号失败');
//    }
//
    /*管理员审核用户的实名认证信息*/
    public function verifyAuthentication(array $data): array
    {
        $_where['id'] = $data['id'];
        $_where['status'] = 1;
        $userInfo = User::where($_where)->first();
        if(!$userInfo){
            return auto_failure(null, '该用户信息不存在');
        }
        $other_info = json_decode($userInfo['other_info'], true);
        if(!isset($other_info['authen_status']) && $other_info['authen_status'] != 0){
            return auto_failure(null, '该用户未提交实名认证信息');
        }

        $other_info['authen_status'] = $data['status'];
        $saveData['other_info'] = json_encode($other_info);
        $res = User::where($_where)->update($saveData);

        return auto_return($res);
    }

    /*获取不同状态下的实名认证列表*/
    public function getAuthticationList($data): array
    {
        $_where['status'] = 1;
        $_where['other_info->authen_status'] = $data['status'];
        $query = User::where($_where);
        if($data['keywords']){
            $keyword = $data['keywords'];
            $query->where(function ($query) use ($keyword) {
                $query->where('name','like',"%".$keyword."%")->orWhere('nickname','like',"%".$keyword."%")->orWhere('other_info->real_name','like',"%".$keyword."%")->orWhere('other_info->authentication->id_number','like',"%".$keyword."%");
            });
        }
        $list = $query
            ->select('id','name','nickname','sex','head_portrait','phone','other_info','other_info->authen_status','other_info->authentication')
            ->orderBy('other_info->authentication->create_time','desc')
            ->paginate($data['list_rows'], null, null, $data['page'])
            ->toArray();
        if($list['total'] > 0){
            foreach ($list['data'] as $k => &$v) {
                $v['other_info'] = json_decode($v['other_info'], true);
                $v['other_info_authentication'] = json_decode($v["`other_info`->'$.\"authentication\"'"], true);
                $v['other_info_authentication']['create_time'] && $v['other_info_authentication']['create_time'] = date('Y-m-d', $v['other_info_authentication']['create_time']);
                $v['other_info_authentication']['update_time'] && $v['other_info_authentication']['update_time'] = date('Y-m-d', $v['other_info_authentication']['update_time']);
                $v['other_info_authen_status_text'] = $this->_getAuthenStatusText($v["`other_info`->'$.\"authen_status\"'"]);
            }
        }
        return auto_return_page($list, '成功获取实名认证列表', '获取实名认证列表失败');
    }

    //这里用于获取实名认证的状态文字
    private function _getAuthenStatusText($authen_status): string
    {
        $authen_status_text = '';
        if($authen_status == -1){
            $authen_status_text = '未提交';
        }elseif($authen_status == 0){
            $authen_status_text = '待审核';
        }elseif($authen_status == 1){
            $authen_status_text = '审核通过';
        }elseif($authen_status == 2){
            $authen_status_text = '审核失败';
        }else{
            $authen_status_text = '未知错误';
        }
        return $authen_status_text;
    }
//
//    /*获取我的账户安全级别 添加两个字段 最后一次修改登录密码的时间 最后一次修改支付密码的时间*/
//    public function getSecurityLevel($data): array
//    {
//        $level_text = '中等';
//        $isAutonym = false;
//        $_where['id'] = $data['user_id'];
//        $_where['status'] = 1;
//        $userInfo = $this->model($this->userModel)->where($_where)->find();
//        $other_info = json_decode($userInfo['other_info'], true);
//        if(isset($other_info['authen_status']) && $other_info['authen_status'] == 1){
//            $isAutonym = true;   //是否进行了实名认证的标识
//        }
//        $loginMsg = bcsub(NOW,$userInfo['update_login_pwd_time']) > 86400 ? '您已超过一个月未更换密码，建议您定期更改密码以保护账户安全' : '互联网账号存在被盗风险，建议您定期更改密码以保护账户安全';
//        $isUpdatePayPwd = $userInfo['update_pay_pwd_time'] ? true : false;   //是否修改了支付密码
//        $payPwdMsg = $isUpdatePayPwd ? '建议您定期更改支付密码以保护账户安全' : '您的支付密码仍为初始密码，建议更改支付密码以保护账户安全';
//        if($isUpdatePayPwd && $isAutonym){
//            $level_text = '较高';
//        }elseif(!$isUpdatePayPwd && !$isAutonym){
//            $level_text = '较低';
//        }
//        $res['level_text'] = $level_text;
//        $res['is_autonym'] = $isAutonym;
//        $res['is_updatePayPwd'] = $isUpdatePayPwd;
//        $res['login_msg'] = $loginMsg;
//        $res['pay_pwd_msg'] = $payPwdMsg;
//        return auto_return($res, '成功获取我的账户安全级别', '获取我的账户安全级别失败');
//    }
//
    /**
     * 获取最近一周的用户增量和用户总数%y-%m-%d
     * @param $data
     * @return array
     * @throws \Exception
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public function userIncreTendency($data): array
    {

        $dbDateFormat = $data['dbDateFormat'];
        $queryRes = DB::select('select count(*) as counts, FROM_UNIXTIME(create_time, :dbDateFormat) as create_time_date from user where create_time > UNIX_TIMESTAMP(DATE_SUB(CURDATE(), INTERVAL 1 WEEK)) group by create_time_date', ['dbDateFormat' => $dbDateFormat]);

        $weeks = week_key_array($data['dateFormat']);
        $delQueryRes = [];
        foreach ($queryRes as $k => $v) {
            $delQueryRes[$v->create_time_date] = $v->counts;
        }

        $weekIncre = array_merge($weeks, $delQueryRes);
        $newWeekIncre = [];
        foreach ($weekIncre as $k => $v) {
            $one['date'] = $k;
            $one['value'] = $v;
            $newWeekIncre[] = $one;
        }
        $res['weekIncre'] = $newWeekIncre;
        $res['total'] = User::count();
        return auto_return($res);

    }
    // 后台添加管理员
    public function addManager($data)
    {
        $res = User::orderBy('id','desc')->select('uuid')->first()->toArray();
        if (empty($res['uuid'])) {
            $data['uuid'] = date('Y').'00001';
        }else{
            $data['uuid'] = $res["uuid"]+1;
        }
       // dd($data);
        //注册时判断手机号是否唯一
        $userInfo = User::where(['phone'=>$data['phone']])->get()->toArray();
        if(!empty($userInfo)){
            return verify_err(null, '该手机号已存在');
        }
        $checkName = User::where(['name'=>$data['name']])->get()->toArray();
        if(!empty($checkName)){
            return verify_err(null, '该用户名已存在');
        }

        $loginPasswordArr = $this->_makeLoginPassword($data['login_password']=$data['phone']);
        $data = array_merge($data, $loginPasswordArr);
        $data['other_info'] = json_encode(['authen_status'=>-1]);  //未提交实名认证
       // $data['role_ids'] = config('tpproject.append_role_ids');
        $data['role_group_ids'] = config('tpproject.append_role_group_ids');
        $data['status'] = USER_REGISTER_STATUS;
        $data['update_login_pwd_time'] = NOW;
        $data['update_pay_pwd_time'] = NOW;
        $data['create_time'] = NOW;
        $data['update_time'] = NOW;
        // 获取管理员id
        $maxId = User::where('id', '<', 1000)->max('id');
        $data['id'] = $maxId + 1;
        try{
            $res = User::insert($data);
        }catch (\Exception $e) {
            // 当唯一键重复等报错时
            return server_err(null, '数据库异常:' . $e->getMessage());
        }

        return auto_return($res, '用户注册成功', '用户注册失败');
    }

    // 后台添加客户端用户信息
    public function addClientUser($data): array
    {
        unset($data['token']);
        $data['check_man'] = session('username');
        $data['status'] = 2;
        $data['create_at'] = date("Y-m-d H:i:s");
        $data['signed_time'] = date("Y-m-d");
        $data['password'] = (new BcryptHasher())->make($data['phone']);
        $data['expired_time'] = strtotime("+".$data['sign_time']." year");
        $data['check_time'] = date("Y-m-d");
        $data['user_name'] = $data['phone'];
        $data['type'] = 1;
        //初始化users表
        DB::beginTransaction();
        try {
            $res = UsersInfo::insertGetId($data);
            $usersData = [
                'info_id' => $res,
                'uuid' => rand_string(32)
            ];
            $rst1 = Users::insert($usersData);
        } catch (\Exception $e) {
            DB::rollBack();
            return auto_failure($e->getMessage());
        }
        if ($res && $rst1) {
            DB::commit();
            $ali = AliController::aliSmsAccount($data['phone']);
            $aliRes = json_decode($ali);
            if($aliRes->Code!="OK"){
                Log::info($data['phone'].'发送失败');
                return auto_failure($data['phone'],'发送短信失败');
            }
            return auto_return(['id' => $res],'添加成功！');
        } else {
            DB::rollBack();
            return auto_failure('添加失败');
        }
    }

    //根据id查询客户详情
    public function userClientDetail($data){
        $users = UsersInfo::with(['deal'=>function($query){
            $query->select('user_id', 'deal_type', 'create_at', 'remark')->where('type', '=', '用户');
        }])->where('id', '=', $data['id'])->get()->toArray();
        $res = UsersInfo::find($data['id'])->callRecord()->get()->toArray();
        $users[0]['call_record'] = $res;
        return auto_return($users, '领取任务成功', '领取任务失败');
    }

    //根据id编辑客户详情
    public function userEditDetail($data){
        unset($data['token']);
        $user = UsersInfo::where('id',$data['id'])->update($data);
        return auto_return($user, '信息修改成功', '信息未编辑或修改失败！');
    }

    //领取任务
    public function userGetTask(){
        $users = UsersInfo::where('status', '=', 0)->orderBy('id')->limit(10)->get()->toArray();
        UsersInfo::where('status', '=', 0)->orderBy('id')->limit(10)->update(['status'=>1,'check_man'=>session('username')]);
        return auto_return($users, '领取任务成功', '领取任务失败');
    }

    //用户审核统计
    public function userCheck(){
        $beginDate = date('Y-m-01');
        $endDate = date('Y-m-d', strtotime("$beginDate +1 month -1 day"));
        $monthPass = UsersInfo::where('status', '=', 2 )->where('check_time','>',$beginDate)->where('check_time','<',$endDate)->where('check_man', '=',session('username'))->count();
        $monthRefuse = UsersInfo::where('status', '=', 4 )->where('check_time','>',$beginDate)->where('check_time','<',$endDate)->where('check_man', '=',session('username'))->count();
        $todayPass = UsersInfo::where('status', '=', 2 )->where('check_time', '=', date('Y-m-d'))->where('check_man', '=',session('username'))->count();
        $todayRefuse = UsersInfo::where('status', '=', 4 )->where('check_time', '=', date('Y-m-d'))->where('check_man', '=',session('username'))->count();
        $monthPassAll = UsersInfo::where('status', '=', 2 )->where('check_time','>',$beginDate)->where('check_time','<',$endDate)->count();
        $monthPrecent = $monthPassAll ? round($monthPass/$monthPassAll*100, 2).'%':'0%';
        $todayPassAll = UsersInfo::where('status', '=', 2 )->where('check_time', '=', date('Y-m-d'))->count();
        $todayPrecent = $todayPassAll ? round($todayPass/$todayPassAll*100, 2).'%':'0%';
        $currentCheck = UsersInfo::where('status', '=', 0 )->count();
        $myCheck = UsersInfo::where('status', '=', 2 )->where('check_man', '=',session('username'))->count();
        $arr=[$monthPass,$monthRefuse,$todayPass,$todayRefuse,$monthPrecent,$todayPrecent,$currentCheck,$todayPassAll,$myCheck];
        return auto_return($arr, '成功', '失败');
    }

    //根据电话状态返回客户
    public function userClientList($data){
        if($data['phone_status']==6){
            $users = UsersInfo::where('status', '=', 1)->where('check_man','=',session('username'))->get()->toArray();
        }else {
            $users = UsersInfo::where('phone_status', '=', $data['phone_status'])->where('status', '=', 4)->where('check_man','=',session('username'))->get()->toArray();
        }
        return auto_return($users,'返回用户成功', '返回用户失败');
    }

    //审核用户
    public function checkClientUser($data){
        unset($data['token']);
       if(!empty($data['phone_status'])){
           return $this->updatePhoneStatus($data);
       }elseif (!empty($data['nopass'])){
           unset($data['nopass']);
           return $this->updateRefuse($data);
       }else{
           return $this->updatePass($data);
       }
    }

    //修改通话状态
    public function updatePhoneStatus($data){
        $user = UsersInfo::where('id',$data['id'])->update(['phone_status'=>$data['phone_status'],'status'=>4,'check_man'=>session('username')]);
        return auto_return(['id'=>$user],'修改成功', '修改失败');
    }

    //修改拒绝内容
    public function updateRefuse($data){
        $data['status'] = 4;
        $user = UsersInfo::where('id',$data['id'])->update($data);
        return auto_return(['id'=>$user],'修改成功', '修改失败');
    }

    //修改通过内容
    public function updatePass($data){
        $data['status'] = 2;
        $data['signed_time'] = date('Y-m-d');
        $data['check_time'] = date('Y-m-d');
        $data['expired_time'] = strtotime("+".$data['sign_time']." year");
        $users = UsersInfo::where('id',$data['id'])->get()->toArray();
        $path = $this->makeProtocol($users,$data['card']);
        $data['agreement'] = $path;
        $res = UsersInfo::where('id', $data['id'])->update($data);
        $ali = AliController::aliSmsAccount($users[0]['phone']);
        $aliRes = json_decode($ali);
        if($aliRes->Code!="OK"){
            Log::info($users[0]['phone'].'发送失败');
            return auto_failure($users[0]['phone'],'发送短信失败');
        }
        return auto_return($res,'修改成功', '修改失败');
    }

    //生成协议
    public function makeProtocol($data,$card){
        $templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor(storage_path('artist_protocol.docx'));
        $templateProcessor->setValue('real_name', $data[0]['real_name']);
        $templateProcessor->setValue('stage_name', $data[0]['stage_name']);
        $templateProcessor->setValue('card', $card);
        $templateProcessor->setValue('y', date("Y"));
        $templateProcessor->setValue('m', date('m'));
        $templateProcessor->setValue('d', date('d'));
//        for ($i = 1; $i <= $count; $i++) {
//            $templateProcessor->setValue('id#' . $i, $i);
//            $templateProcessor->setValue('isrc#' . $i, '');
//            $templateProcessor->setValue('album#' . $i, $data[$i - 1]['album']);
//            $templateProcessor->setValue('title#' . $i, $data[$i - 1]['title']);
//            $templateProcessor->setValue('performer#' . $i, $data[$i - 1]['performer']);
//            $templateProcessor->setValue('check_time#' . $i, $check_time1);
//            $templateProcessor->setValue('writer#' . $i, $data[$i - 1]['writer']);
//            $templateProcessor->setValue('composer#' . $i, $data[$i - 1]['composer']);
//            $templateProcessor->setValue('neighboring_right_2#' . $i, $data[$i - 1]['neighboring_right_2'] . '%');
//            $templateProcessor->setValue('neighboring_right_3#' . $i, $data[$i - 1]['neighboring_right_3'] . '%');
//            $templateProcessor->setValue('neighboring_right_1#' . $i, $data[$i - 1]['neighboring_right_1'] . '%');
//            $templateProcessor->setValue('video#' . $i, "100%");
//            $templateProcessor->setValue('time#' . $i, $check_time1 . '-' . $expired_time);
//        }
        $rand = rand_string(4);
        $templateProcessor->saveAs( 'uploads/files/'.date('Y-m-d') .'-'.$rand. '.docx');
        $objReader = \PhpOffice\PhpWord\IOFactory::createReader('Word2007');
        return 'uploads/files/'.date('Y-m-d') .'-'.$rand. '.docx';
        //生成pdf版式错乱
//        $phpWord = $objReader->load(storage_path( date('Y-m-d') . '.docx'));
//        $phpWord = new \PhpOffice\PhpWord\PhpWord();
//        $section = $phpWord->addSection();
//       // $desc = "Learn from yesterday, live for today, hope for tomorrow.";
//        $section->addText('授权书');
//        $section->addText(
//                       '授权书',
//                [
//                    'name' => '宋体',
//                    'size' => 16,
//                    'bold' => true,
//                 ]
//        );
//        $rendererName = \PhpOffice\PhpWord\Settings::PDF_RENDERER_TCPDF;
//        $rendererLibraryPath = 'tcpdf';
//        \PhpOffice\PhpWord\Settings::setPdfRenderer($rendererName,$rendererLibraryPath);
//        \PhpOffice\PhpWord\Settings::setDefaultFontSize(13);
//        \PhpOffice\PhpWord\Settings::DEFAULT_FONT_CONTENT_TYPE;
//        $objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord,'PDF');
//        $objWriter->save(storage_path($simple_name . date('Y-m-d') .".pdf"));
    }

    //修改用户信息
    public function updateUser($data){

    }

    //用户联系时间
    public function userPhoneTime(){
        $phone_time[] = UsersInfo::where('phone_time',0)->count();
        $phone_time[] = UsersInfo::where('phone_time',1)->count();
        $phone_time[] = UsersInfo::where('phone_time',2)->count();
        $phone_time[] = UsersInfo::where('phone_time',3)->count();
        return auto_return($phone_time,'返回成功', '返回失败');
    }

    //用户列表
    public function userList($data){
        $now = strtotime("now");
        $nextmonth = strtotime("+3 months", strtotime("now"));
        $premonth = strtotime("-3 months", strtotime("now"));
        if(!empty($data['status'])){
            $query = UsersInfo::withCount('music')->where('status','=',$data['status']);
        }else{
            $query = UsersInfo::withCount('music')->whereIn('status',[2,3]);
        }
        !empty($data['real_name']) && $query->where('real_name','=',$data['real_name']);
        !empty($data['phone']) && $query->where('phone','=',$data['phone']);
        !empty($data['stage_name']) && $query->where('stage_name','=',$data['stage_name']);
        !empty($data['signed_time']) && $query->where('signed_time','=',$data['signed_time']);
        !empty($data['country']) && $query->where('country','=',$data['country']);
        !empty($data['type']) && $query->where('type','=',$data['type']);
        !empty($data['check_man']) && $query->where('check_man','=',$data['check_man']);
        !empty($data['come_from']) && $query->where('come_from','=',$data['come_from']);
        !empty($data['expired']) && $query->where('expired_time','<',$now);
        !empty($data['expired2']) && $query->where('expired_time','<',$nextmonth)->where('expired_time','>',$premonth);
        $users = $query->paginate(10);
        return auto_return($users,'返回成功', '返回失败');
    }
}
